package com.ayf.payment.game.api.eqb.service;

import cn.hutool.core.date.DateUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ayf.payment.game.api.cache.redis.RedisCacheUtil;
import com.ayf.payment.game.api.entity.Merchant;
import com.ayf.payment.game.api.entity.MerchantSign;
import com.ayf.payment.game.api.eqb.comm.HttpCfgHelper;
import com.ayf.payment.game.api.eqb.comm.SignDTO;
import com.ayf.payment.game.api.eqb.constant.CacheKeyConstant;
import com.ayf.payment.game.api.eqb.constant.ConfigConstant;
import com.ayf.payment.game.api.eqb.exception.DefineException;
import com.ayf.payment.game.api.eqb.helper.AccountHelper;
import com.ayf.payment.game.api.eqb.helper.FileTemplateHelper;
import com.ayf.payment.game.api.eqb.helper.SignHelper;
import com.ayf.payment.game.api.eqb.helper.TokenHelper;
import com.ayf.payment.game.api.exception.LogicalException;
import com.ayf.payment.game.api.exception.ParameterException;
import com.ayf.payment.game.api.service.MerchantService;
import com.ayf.payment.game.api.service.MerchantSignService;
import com.ayf.payment.game.api.utils.FtpUtil;
import com.ayf.payment.game.api.utils.SensitiveDataUtil;
import com.ayf.payment.game.api.utils.SnowFlakeUtils;
import com.google.common.collect.Lists;
import com.swwx.charm.commons.lang.utils.LogPortal;
import org.apache.commons.lang3.StringUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @Author: zh-liang
 * @Date : 2020-06-14 19:23
 */
@Component
public class EQBServiceImpl implements EQBService {

    @Resource
    private RedisCacheUtil redisCacheUtil;
    @Resource
    private MerchantSignService merchantSignService;
    @Resource
    private MerchantService merchantService;

    @Override
    public String getToken() {
        String traceId = SnowFlakeUtils.getUniqueId();
        try {
            String token = redisCacheUtil.getObjectFromCache(CacheKeyConstant.TOKEN);
            if (StringUtils.isEmpty(token)) {
                JSONObject tokenData = TokenHelper.getTokenData();
                redisCacheUtil.setObjectToCache(CacheKeyConstant.TOKEN, tokenData.getString("token"), 100L, TimeUnit.MINUTES);
                redisCacheUtil.setObjectToCache(CacheKeyConstant.REFRESH_TOKEN, tokenData.getString("refreshToken"), 100L, TimeUnit.MINUTES);
                return tokenData.getString("token");
            } else {
                return token;
            }
        } catch (Exception e) {
            throw new LogicalException("E签宝获取token失败，发送[{}],异常信息为[{}]", traceId, e.getClass().getSimpleName(), e.getMessage());
        }
    }

    @Override
    public String getSignUrl(SignDTO signDTO) {

        String traceId = SnowFlakeUtils.getUniqueId();

        try {
            MerchantSign dbInfo = merchantSignService.getMerSignInfo(signDTO.getMerchantId());
            String acctId = dbInfo.getChannelAccountId();
            if (StringUtils.isEmpty(acctId)) {
                acctId = createAccount(signDTO, acctId);
            } else if (!signDTO.getIdCardNo().equals(dbInfo.getIdCard())) {
                acctId = createAccount(signDTO, acctId);
            } else {
                LogPortal.info("---------------------修改个人账号start-------------------------------");
                JSONObject moDa = AccountHelper.updatePersonAcctByAcctId(acctId, null, signDTO.getPhone(), signDTO.getName());
                LogPortal.info("修改注册信息返回：{}", moDa.toJSONString());
                LogPortal.info("商户：{} 修改易签宝注册信息成功", signDTO.getMerchantId());
            }
            LogPortal.info("---------------------通过模板创建文件start-----------------------------");

            Map<String, String> map = new HashMap<>();
            map.put("e_name", signDTO.getName());
            map.put("e_id_card", signDTO.getIdCardNo());
            map.put("e_phone", signDTO.getPhone());
            map.put("e_email", signDTO.getEmail());
            map.put("e_id", signDTO.getMerchantId().toString());
            Merchant merchantDTO = merchantService.find(signDTO.getMerchantId());
            map.put("e_data", DateUtil.format(merchantDTO.getCreateTime(), "yyyy年MM月dd日"));
            map.put("e_data_2", DateUtil.format(merchantDTO.getCreateTime(), "yyyy年MM月dd日"));
            JSONObject fileByTemplateId = FileTemplateHelper.createFileByTemplateId("平台使用协议-" + signDTO.getName() + ".pdf",
                    ConfigConstant.TEMPLATE_ID, map);

            String fileId = fileByTemplateId.getString("fileId");


            /***
             * 搜索关键字坐是辅助接口，用于根据关键字辅助定位签署区的坐标位置。
             * **/
            LogPortal.info("---------------------搜索关键字坐标 start-----------------------------");
            SignHelper.searchWordsPosition(fileId, "甲方");


            LogPortal.info("---------------------签署流程创建 start---------------------------------");
            //可通过SignParamUtil.createSignFlowStart()进行组装入参，具体使用中根据实际情况传参
            JSONObject flowJson = SignHelper.createSignFlow(signDTO.getName());
            String flowId = flowJson.getString("flowId");

            LogPortal.info("---------------------流程文档添加 start---------------------------------");
            SignHelper.addFlowDoc(flowId, fileId);

            /****
             注：平台自动盖章是要用你们平台的章，这里代码印章id没有传，会取实名注册的公司的默认印章。正式环境是你们自己的印章可以在官网设置，您的用户签署用关于添加用户签署区的接口。
             ****/
            LogPortal.info("---------------------添加平台自动盖章签署区 start---------------------------");
            SignHelper.addPlatformAutoSignArea(flowId, Lists.newArrayList(fileId), Lists.newArrayList(""));

            /***
             * 此接口是用户的手动签署接口，用于添加您的客户的签署。
             ****/

            LogPortal.info("---------------------添加手动盖章签署区 start-----------------------------");
            SignHelper.addSignerHandSignArea(flowId, Lists.newArrayList(fileId), Lists.newArrayList(acctId), null);


            LogPortal.info("---------------------签署流程开启 start-----------------------------");
            SignHelper.startSignFlow(flowId);

            /****
             说明：
             流程开启后，手动盖章签署区的签署h5链接可以通过【获取签署地址】接口获取，此demo里演示的会根据创建账号里传入的手机号发送带有签署短链接的短信进行签署。
             然后客户签署后可进行以下两步：归档流程及签署文件下载
             ****/
            JSONObject signJSON = SignHelper.qrySignUrl(flowId, acctId, "", "0");
            String url = signJSON.getString("shortUrl");
            if (StringUtils.isNotBlank(url)) {
                LogPortal.error("[{}]用户[{}][{}]获取签署协议URL成功，url:[{}]", traceId, signDTO.getName(),
                        signDTO.getIdCardNo(), url);
            }

            MerchantSign sign = new MerchantSign();
            sign.setMerchantId(signDTO.getMerchantId());
            sign.setChannelAccountId(acctId);
            sign.setName(signDTO.getName());
            sign.setIdCard(signDTO.getIdCardNo());
            sign.setEmail(signDTO.getEmail());
            sign.setPhone(signDTO.getPhone());
            sign.setChannelFlowId(flowId);
            merchantSignService.updateMerSign(sign);
            return url;
        } catch (ParameterException e) {
            throw e;
        } catch (Exception e) {
            LogPortal.error("[{}]用户[{}][{}]获取签署协议URL失败，发送[{}]异常，异常信息为[{}]", e, traceId, signDTO.getName(),
                    signDTO.getIdCardNo(), e.getClass().getSimpleName(), e.getMessage());
            throw new ParameterException(e.getMessage() + ",错误码" + traceId);
        }
    }

    private String createAccount(SignDTO signDTO, String acctId) throws DefineException {
        LogPortal.info("---------------------查询账号是否存在-------------------------------");
        JSONObject qryPersonAcctByThirdId = AccountHelper.qryPersonAcctByThirdId(signDTO.getIdCardNo());
        int code = qryPersonAcctByThirdId.getIntValue("code");
        if (code == 53000001) {
            LogPortal.info("---------------------查询结果：账号不存在-------------------------------");
            LogPortal.info("---------------------创建个人账号start-------------------------------");
            JSONObject personAcctJson = AccountHelper.createPersonAcct(signDTO.getIdCardNo(), signDTO.getName(), null,
                    signDTO.getIdCardNo(),
                    signDTO.getPhone(), null);
            acctId = personAcctJson.getString("accountId");
        } else if (code == 0) {
            LogPortal.info("---------------------查询结果：账号已存在-------------------------------");
            JSONObject obj = qryPersonAcctByThirdId.getJSONObject("data");
            Boolean status = obj.getBoolean("status");
            acctId = obj.getString("accountId");
            if (status) {
                String name = obj.getString("name");
                if (!signDTO.getName().equals(name)) {
                    String error = "检测到该身份证号已在本平台实名，请填写正确姓名：" + SensitiveDataUtil.accountNameDesensitization(name);
                    throw new ParameterException(error);
                }
            } else {
                LogPortal.info("---------------------修改个人账号start-------------------------------");
                JSONObject moDa = AccountHelper.updatePersonAcctByAcctId(acctId, null, signDTO.getPhone(), signDTO.getName());
                LogPortal.info("修改注册信息返回：{}", moDa.toJSONString());
                LogPortal.info("商户：{} 修改易签宝注册信息成功", signDTO.getMerchantId());
            }
        }
        return acctId;
    }

    @Override
    public void archiveFlow(String traceId, String flowId, String accId) {
        try {
            LogPortal.info("---------------------平台方进行签署流程归档 start-----------------------------");
            SignHelper.archiveSignFlow(flowId);
        } catch (Exception e) {
            LogPortal.error("[{}]accId[{}],flowId[{}]签署流程归档失败，发生[{}]异常，异常信息为[{}]", traceId, accId, flowId,
                    e.getClass().getSimpleName(),
                    e.getMessage());
        }
    }

    @Override
    public String downloadDoc(String traceId, String flowId, String accId) {
        try {
            LogPortal.info("---------------------归档后，获取文件下载地址 start-----------------------------");
            JSONObject jsonObject = SignHelper.downloadFlowDoc(flowId);
            JSONArray docs = jsonObject.getJSONArray("docs");
            JSONObject jsonObject1 = JSON.parseObject(docs.get(0).toString());
            return jsonObject1.getString("fileUrl");
        } catch (Exception e) {
            LogPortal.error("[{}]accId[{}],flowId[{}]归档后，获取文件下载地址归档后，获取文件下载地址失败，发生[{}]异常，异常信息为[{}]", traceId, accId,
                    flowId,
                    e.getClass().getSimpleName(),
                    e.getMessage());
        }
        return null;
    }

    @Async
    @Override
    public void asyncHandle(String traceId, String accId, String flowId, Integer signResult, Date signTime) {
        try {
            MerchantSign sign = new MerchantSign();
            sign.setChannelAccountId(accId);
            if (signResult == 2) {
                sign.setContractStatus(1);

                archiveFlow(traceId, flowId, accId);
                String url = downloadDoc(traceId, flowId, accId);
                byte[] bytes = HttpCfgHelper.down(url);
                if (bytes != null) {
                    String fileName =SnowFlakeUtils.getTraceId() + ".pdf";
                    FtpUtil.uploadXYFile(bytes,fileName, "/pdf",traceId);
                    sign.setContractFileUrl(fileName);
                }
            } else if (signResult == 3) {
                sign.setContractStatus(2);
            } else if (signResult == 4) {
                sign.setContractStatus(3);
            }
            sign.setContractTime(signTime);
            sign.setContractFlowId("XY" + traceId);
            sign.setChannelFlowId(flowId);

            merchantSignService.updateMerAuthByFlowId(sign);

            LogPortal.info("[{}]E签宝-协议签署结果通知成功-异步处理成功,accId[{}]", traceId, accId);
        } catch (Exception e) {
            LogPortal.error("[{}]E签宝-协议签署结果通知成功-异步处理失败,accId[{}],发生[{}],异常信息为[{}]", traceId, accId,
                    e.getClass().getSimpleName(),
                    e.getMessage());
        }
    }
}
